]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
notifications: Add buttons to Calendar.NotificationMessage via actions
authorJulian Sparber <julian@sparber.net>
Wed, 21 Feb 2024 11:07:10 +0000 (12:07 +0100)
committerFlorian Müllner <fmuellner@gnome.org>
Sun, 3 Mar 2024 01:33:16 +0000 (01:33 +0000)
Since we also want to show the buttons in the calendar move the
code to add buttons/actions from `MessageTray.NotificationBanner` to
`Calendar.NotificationMessage`.

As nothing uses custom buttons that aren't backed by actions anymore,
remove that bit of the public API.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/7099
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3173>

data/theme/gnome-shell-sass/widgets/_notifications.scss
js/ui/calendar.js
js/ui/messageList.js
js/ui/messageTray.js

index a5497e20f0e3b8ddfe9598bbff4a40446f88aa3c..0601425ba2387c4072569ce8c3707fc2c72c05d3 100644 (file)
@@ -14,12 +14,12 @@ $notification_banner_width: 34em;
   @if $contrast == 'high' {
     @include draw_hc_inset();
   }
+}
 
-  .notification-actions {
-    spacing: 0;
-  }
+.notification-buttons-bin {
+  spacing: 0;
+}
 
-  .notification-button {
-    @extend %bubble_button;
-  }
+.notification-button {
+  @extend %bubble_button;
 }
index c0b62d540ae5d4cef932df53407ccbf0f2db877f..dcf8606513691ffd6b1859292e6812f327d3cc8e 100644 (file)
@@ -18,6 +18,7 @@ import {formatDateWithCFormatString} from '../misc/dateUtils.js';
 import {loadInterfaceXML} from '../misc/fileUtils.js';
 
 const SHOW_WEEKDATE_KEY = 'show-weekdate';
+const MAX_NOTIFICATION_BUTTONS = 3;
 
 const NC_ = (context, str) => `${context}\u0004${str}`;
 
@@ -782,11 +783,19 @@ class NotificationMessage extends MessageList.Message {
         });
         notification.connectObject(
             'updated', this._onUpdated.bind(this),
+            'action-added', (_, action) => this._addAction(action),
+            'action-removed', (_, action) => this._removeAction(action),
+
             'destroy', () => {
                 this.notification = null;
                 if (!this._closed)
                     this.close();
             }, this);
+
+        this._actions = new Map();
+        this.notification.actions.forEach(action => {
+            this._addAction(action);
+        });
     }
 
     _getIcon() {
@@ -815,6 +824,36 @@ class NotificationMessage extends MessageList.Message {
     canClose() {
         return true;
     }
+
+    _addAction(action) {
+        if (!this._buttonBox) {
+            this._buttonBox = new St.BoxLayout({
+                x_expand: true,
+                style_class: 'notification-buttons-bin',
+            });
+            this.setActionArea(this._buttonBox);
+            global.focus_manager.add_group(this._buttonBox);
+        }
+
+        if (this._buttonBox.get_n_children() >= MAX_NOTIFICATION_BUTTONS)
+            return;
+
+        const button = new St.Button({
+            style_class: 'notification-button',
+            x_expand: true,
+            label: action.label,
+        });
+
+        button.connect('clicked', () => action.activate());
+
+        this._actions.set(action, button);
+        this._buttonBox.add_child(button);
+    }
+
+    _removeAction(action) {
+        this._actions.get(action)?.destroy();
+        this._actions.delete(action);
+    }
 });
 
 const NotificationSection = GObject.registerClass(
index b5ee41cd7f2e824e63ca5117e995ad7e51fcca32..37254f72e90c5481d9bcd4538ef7823e167b4c66 100644 (file)
@@ -469,7 +469,7 @@ export const Message = GObject.registerClass({
         });
         vbox.add_child(hbox);
 
-        this._actionBin = new St.Widget({
+        this._actionBin = new St.Bin({
             layout_manager: new ScaleLayout(),
             visible: false,
         });
@@ -557,17 +557,8 @@ export const Message = GObject.registerClass({
     }
 
     setActionArea(actor) {
-        if (actor == null) {
-            if (this._actionBin.get_n_children() > 0)
-                this._actionBin.get_child_at_index(0).destroy();
-            return;
-        }
-
-        if (this._actionBin.get_n_children() > 0)
-            throw new Error('Message already has an action area');
-
-        this._actionBin.add_child(actor);
-        this._actionBin.visible = this.expanded;
+        this._actionBin.child = actor;
+        this._actionBin.visible = actor && this.expanded;
     }
 
     addMediaControl(iconName, callback) {
@@ -583,7 +574,7 @@ export const Message = GObject.registerClass({
     expand(animate) {
         this.expanded = true;
 
-        this._actionBin.visible = this._actionBin.get_n_children() > 0;
+        this._actionBin.visible = !!this._actionBin.child;
 
         const duration = animate ? MessageTray.ANIMATION_TIME : 0;
         this._bodyStack.ease_property('@layout.expansion', 1, {
index 72db9579e0f4195cd936465e4cfa00077c6df394..48731367ac0d1730a67bc6d2dfa71e0124eecd42 100644 (file)
@@ -27,7 +27,6 @@ const LONGER_HIDE_TIMEOUT = 600;
 
 const MAX_NOTIFICATIONS_IN_QUEUE = 3;
 const MAX_NOTIFICATIONS_PER_SOURCE = 3;
-const MAX_NOTIFICATION_BUTTONS = 3;
 
 // We delay hiding of the tray if the mouse is within MOUSE_LEFT_ACTOR_THRESHOLD
 // range from the point where it left the tray.
@@ -498,7 +497,18 @@ export const Notification = GObject.registerClass({
     // @label: the label for the action's button
     // @callback: the callback for the action
     addAction(label, callback) {
-        const action = new Action(label, callback);
+        const action = new Action(label, () => {
+            callback();
+
+            // We don't hide a resident notification when the user invokes one of its actions,
+            // because it is common for such notifications to update themselves with new
+            // information based on the action. We'd like to display the updated information
+            // in place, rather than pop-up a new notification.
+            if (this.resident)
+                return;
+
+            this.destroy();
+        });
         this.actions.push(action);
         this.emit('action-added', action);
     }
@@ -557,8 +567,14 @@ export const Notification = GObject.registerClass({
     activate() {
         this.emit('activated');
 
-        if (!this.resident)
-            this.destroy();
+        // We don't hide a resident notification when the user invokes one of its actions,
+        // because it is common for such notifications to update themselves with new
+        // information based on the action. We'd like to display the updated information
+        // in place, rather than pop-up a new notification.
+        if (this.resident)
+            return;
+
+        this.destroy();
     }
 
     destroy(reason = NotificationDestroyedReason.DISMISSED) {
@@ -579,10 +595,6 @@ export const NotificationBanner = GObject.registerClass({
         this.can_focus = false;
         this.add_style_class_name('notification-banner');
 
-        this._buttonBox = null;
-
-        this._addActions();
-
         this.notification.connectObject('activated', () => {
             // We hide all types of notifications once the user clicks on
             // them because the common outcome of clicking should be the
@@ -591,64 +603,6 @@ export const NotificationBanner = GObject.registerClass({
             this.emit('done-displaying');
         }, this);
     }
-
-    _onUpdated(n, clear) {
-        super._onUpdated(n, clear);
-
-        if (clear) {
-            this.setActionArea(null);
-            this._buttonBox = null;
-        }
-
-        this._addActions();
-    }
-
-    _addActions() {
-        this.notification.actions.forEach(action => {
-            this.addAction(action.label, () => action.activate());
-        });
-    }
-
-    addButton(button, callback) {
-        if (!this._buttonBox) {
-            this._buttonBox = new St.BoxLayout({
-                style_class: 'notification-actions',
-                x_expand: true,
-            });
-            this.setActionArea(this._buttonBox);
-            global.focus_manager.add_group(this._buttonBox);
-        }
-
-        if (this._buttonBox.get_n_children() >= MAX_NOTIFICATION_BUTTONS)
-            return null;
-
-        this._buttonBox.add_child(button);
-        button.connect('clicked', () => {
-            callback();
-
-            if (!this.notification.resident) {
-                // We don't hide a resident notification when the user invokes one of its actions,
-                // because it is common for such notifications to update themselves with new
-                // information based on the action. We'd like to display the updated information
-                // in place, rather than pop-up a new notification.
-                this.emit('done-displaying');
-                this.notification.destroy();
-            }
-        });
-
-        return button;
-    }
-
-    addAction(label, callback) {
-        const button = new St.Button({
-            style_class: 'notification-button',
-            label,
-            x_expand: true,
-            can_focus: true,
-        });
-
-        return this.addButton(button, callback);
-    }
 });
 
 export const Source = GObject.registerClass({